/**
 * @author harry
 * @date 2022/2/23/21:46
 */

package com.serviceOrchestration.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.serviceOrchestration.pojo.Account;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class JwtUtil {
    public static final long EXPIRATION = 10 * 60 * 1000;
    private static final String SALT = "service-orchestration";
    private static final Algorithm algorithm = Algorithm.HMAC256(SALT);
    private static final Map<String, JWTVerifier> verifiers = new HashMap<>();
    private static final String ROLE = "role";
    private static final String IP = "ip";

    /**
     * 生成新token
     * @param account 用户或管理员
     * @return token
     */
    public static String generateToken(Account account) {
        return generateToken(account, null);
    }

    public static String generateToken(Account account, String ip) {
//        Date expirationTime = new Date(System.currentTimeMillis() + EXPIRATION);
        JWTCreator.Builder builder = JWT.create()
                .withSubject(account.getId())
//                .withExpiresAt(expirationTime)
                .withClaim(ROLE, account.getRole());
        if(ip != null) builder.withClaim(IP, ip);
        return builder.sign(algorithm);
    }



    /**
     * 从token中获取信息，校验token有效性：编码、是否过期、是否有sub和role...
     * @param token 可为空
     */
    public static boolean verifyToken(String token) {
        log.info("got token: " + token);
        if(token == null) return false;
        try {
            DecodedJWT jwt = JWT.decode(token); // JWTDecodeException: utf-8/base64 encode exception
            log.info("verifying... claims=" + jwt.getClaims().toString());

            Claim roleClaim = jwt.getClaim(ROLE);
            String subject = jwt.getSubject();
            if(roleClaim.isNull() || subject == null) return false;
            String role = roleClaim.asString();
            // TODO 后期考虑重构：是否有这个账号的单例存在，没有则创建单例
            JWTVerifier theVerifier = JWT.require(algorithm)
                    .withSubject(subject)
                    .withClaim(ROLE, role)
                    .build();
            theVerifier.verify(token); // JWTVerificationException
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取subject
     * @param token 原token字符串
     * @return String 或 null
     */
    public static String getSubjectFromToken(String token) {
        if(token == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getSubject();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取subject
     * @param jwt 解码后的jwt
     * @return String 或 null
     */
    public static String getSubjectFromToken(DecodedJWT jwt) {
        if(jwt == null) return null;
        return jwt.getSubject();
    }

    public static String getRoleFromToken(String token) {
        return getClaimFromToken(token, ROLE);
    }

    public static String getIpFromToken(String token) {
        return getClaimFromToken(token, IP);
    }

    public static String getRoleFromToken(DecodedJWT jwt) {
        return getClaimFromToken(jwt, ROLE);
    }

    public static String getClaimFromToken(String token, String claimName) {
        if(token == null || claimName == null) return null;
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claimName).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    public static String getClaimFromToken(DecodedJWT jwt, String claimName) {
        if(jwt == null || claimName == null) return null;
        Claim claim = jwt.getClaim(claimName);
        return claim.isNull() ? null : claim.asString();
    }
}
